--[[
副本目标逻辑总入口
接口列表：
roomBegin			房间开始
roomClear			房间重置
sendAimList			下发目标列表
sendAimListByHuman  下发目标列表
sendAimStatus		下发目标状态
aimCanAccept		判断目标是否可接
aimDoAccept			接目标
aimCanFinish		判断目标是否可交
aimDoFinish			交目标
aimDoFail			目标失败
aimMonsterDieCB		怪物被打死回调
aimCollectDieCB		采集物被采集回调
aimRoleDieCB		玩家被打死回调
aimTimerOneSec		定时器回调 1秒一次
aimSceneNChange		地图事件n计数改变
getEnterMap			根据目标进度获取进入的mapid, x, y
getAimProgress		获取目标进度
getDoingMainAim		获取正在做的主线副本目标id

aimRoomStatus       roomID -> {aimRecord} 
aimRecord内容 
status 目标状态
[monsterID] 打怪数量 打怪目标中才有
[collectID] 采集数量 采集目标中才有
beginTime	接受时间
--]]

local CopyCallback = require("copy.CallbackL")
local Lang = require("common.Lang")
local Util = require("common.Util")
local Msg = require("core.Msg")
local Map = require("core.Map")
local ObjHuman = require("core.ObjHuman")
local ExcelMapConf = require("excel.Map")
local ExcelCopyAimConf = require("excel.CopyAim")
local ExcelNpcConf = require("excel.Npc")
local ItemDefine = require("bag.ItemDefine")
local Grid = require("bag.Grid")
local GridLogic = require("bag.GridLogic")
local Copy = require("copy.CopyL")
local AimAction = require("copy.AimAction")
local CopyDefine = require("copy.Define")
local Guide  = require("task.Guide")
local BagLogic = require("bag.BagLogic")

aimRoomStatus = aimRoomStatus or {} -- roomID -> {aimRecord}

local RetRewardItem = {}
local RewardItemGridCache = {} -- 奖励道具grid缓存 避免频繁new grid

function roomBegin(copyID, roomID)
	aimRoomStatus[roomID] = {}
			
	local copyConfig = ExcelMapConf.copy[copyID]
	if copyConfig.aim == 0 then return end
	local aimConfig = ExcelCopyAimConf[copyID][copyConfig.aim]	
	if aimConfig == nil then return end
	aimDoAccept(copyConfig.aim, copyID, roomID) -- 自动接起始目标
end

function roomClear(copyID, roomID)
	aimRoomStatus[roomID] = nil
end

-- 下发目标列表
function sendAimListByHuman(human, copyID, roomID)
	if ExcelCopyAimConf[copyID] == nil then return end

	local msgRet = Msg.gc.GC_COPY_AIM_LIST
	local aims = msgRet.aims
	local count = 0
	local aimNode
	for aimID, aimInfo in pairs(ExcelCopyAimConf[copyID]) do
		count = count + 1	
		aimNode = aims[count]
		aimNode.aimID = aimID
		aimNode.name = aimInfo.name
		aimNode.tip = aimInfo.tip
		aimNode.isMain = aimInfo.mainLoop
		aimNode.progress = aimInfo.progress
		
		if aimInfo.startNpcId == 0 then
			aimNode.beginNPC[0] = 0
			aimNode.beginTalk = ""
		else
			aimNode.beginNPC[0] = 1
			aimNode.beginNPC[1].id = aimInfo.startNpcId
			aimNode.beginNPC[1].flag = ExcelNpcConf.npc[aimInfo.startNpcId].exist_map
			aimNode.beginNPC[1].mapID = ExcelNpcConf.npc[aimInfo.startNpcId].mapID
			aimNode.beginNPC[1].mapX = ExcelNpcConf.npc[aimInfo.startNpcId].mapX
			aimNode.beginNPC[1].mapY = ExcelNpcConf.npc[aimInfo.startNpcId].mapY
			aimNode.beginTalk = aimInfo.startTalk
		end
		if aimInfo.endNpcId == 0 then
			aimNode.endNPC[0] = 0
			aimNode.endTalk = ""
		else
			aimNode.endNPC[0] = 1
			aimNode.endNPC[1].id = aimInfo.endNpcId
			aimNode.endNPC[1].flag = ExcelNpcConf.npc[aimInfo.endNpcId].exist_map
			aimNode.endNPC[1].mapID = ExcelNpcConf.npc[aimInfo.endNpcId].mapID
			aimNode.endNPC[1].mapX = ExcelNpcConf.npc[aimInfo.endNpcId].mapX
			aimNode.endNPC[1].mapY = ExcelNpcConf.npc[aimInfo.endNpcId].mapY
			aimNode.endTalk = aimInfo.endTalk
		end
		aimNode.status, aimNode.desc, aimNode.remainTime = AimAction.getStatusInfoByAction(copyID, roomID, aimID, aimNode.taskObj)
		aimNode.totalTime = aimInfo.targetTime
		aimNode.prevAimID = aimInfo.prevAimId
		
		aimNode.taskGuide1 = aimInfo.guide1
		aimNode.taskGuide2 = aimInfo.guide2
		aimNode.taskGuide3 = aimInfo.guide3
		aimNode.taskGuide4 = aimInfo.guide4
		
		Guide.setGuideList(aimInfo.guide1,aimNode.listGuide1)
		Guide.setGuideList(aimInfo.guide2,aimNode.listGuide2)
		Guide.setGuideList(aimInfo.guide3,aimNode.listGuide3)		
		Guide.setGuideList(aimInfo.guide4,aimNode.listGuide4)		
		
		local itemCount, itemGrids = getRewardItem(human, copyID, aimID, aimInfo)		
		aimNode.reward[0] = itemCount
		for i = 1, itemCount do 
			GridLogic.makeItem(itemGrids[i], aimNode.reward[i], 0)
		end
		aimNode.startTime = 0
		aimNode.target = aimInfo.target
	end
	
	aims[0] = count
	
	Msg.send(msgRet, human.fd)
end

function sendAimList(copyID, roomID)
	local humanList = Copy.getCopyHumanList(copyID, roomID)
	for i = 1, #humanList do
		sendAimListByHuman(humanList[i], copyID, roomID)
	end
end

function sendAimStatus(copyID, roomID, aimID)
	local msgRet = Msg.gc.GC_COPY_AIM_ITEM_UPDATE
	msgRet.aimID = aimID
	msgRet.status, msgRet.desc = AimAction.getStatusInfoByAction(copyID, roomID, aimID, msgRet.taskObj)
	
	Copy.sendCopy(msgRet, copyID, roomID)
	
--  print("sendAim"..aimID.." status.."..msgRet.status.."   dest:"..msgRet.desc.."  cur:",msgRet.taskObj[1] and msgRet.taskObj[1].cur)
end

-- 判断目标是否可接
function aimCanAccept(aimID, copyID, roomID)
	local aimRecord = aimRoomStatus[roomID][aimID]
	
	if aimRecord then
		if aimRecord.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH or
			aimRecord.status == CopyDefine.AIM_STATUS_DOING_CAN_FINISH then
			return CopyDefine.COPY_AIM_ACCEPT_FAIL_ACCEPTED -- 副本目标不可接，已经接过	
		end
	end
	
	if aimRecord and aimRecord.status == CopyDefine.AIM_STATUS_FINISHED then
		return CopyDefine.COPY_AIM_ACCEPT_FAIL_FINISHED -- 副本目标不可接，已经完成
	end 

	local aimConfig = ExcelCopyAimConf[copyID][aimID]
	if aimConfig.prevAimId ~= 0 then
		if aimRoomStatus[roomID][aimConfig.prevAimId] == nil or aimRoomStatus[roomID][aimConfig.prevAimId].status ~= CopyDefine.AIM_STATUS_FINISHED then
			return CopyDefine.COPY_AIM_ACCEPT_FAIL_PREV_AIM -- 任务不可接，前置任务未完成
		end
	end

	return CopyDefine.COPY_AIM_ACCEPT_OK
end

-- 接目标
function aimDoAccept(aimID, copyID, roomID)
	if Copy.roomDatas[copyID][roomID].finishCode then return end

	local copyConfig = ExcelMapConf.copy[copyID]
	local aimConfig = ExcelCopyAimConf[copyID][aimID]
	if not aimConfig then
		assert(nil, aimID)
	end
	if aimConfig.target == CopyDefine.COPY_AIM_ACTION_TALK then -- 对话目标的话一接就自动变成可完成状态了
		aimRoomStatus[roomID][aimID] = {status = CopyDefine.AIM_STATUS_DOING_CAN_FINISH, beginTime = os.time()}
	else
		aimRoomStatus[roomID][aimID] = {status = CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH, beginTime = os.time()}
	end

	AimAction.playMovie(copyID, roomID, aimConfig.movie1)
	AimAction.raiseSceneEvent(copyID, roomID, aimConfig.event1)
	
	sendAimStatus(copyID, roomID, aimID)
	
	if aimConfig.mainLoop == CopyDefine.AIM_TYPE_MAIN then
		-- 看这个主线目标有没有挑战目标
		for tempID, tempConfig in pairs(ExcelCopyAimConf[copyID]) do
			if tempConfig.mainLoop == CopyDefine.AIM_TYPE_CHALLENGE and tempConfig.prevAimId == aimID then
				aimDoAccept(tempID, copyID, roomID)
				-- break
			end
		end
	
		if copyConfig.type == CopyDefine.COPY_TYPE_TEAM or copyConfig.type == CopyDefine.COPY_TYPE_COUPLE then
			-- 更新副本进度
--			for teamid, tempRoomID in pairs(Copy.copyTeam2Room) do
--				if roomID == tempRoomID then
--					CopyTeam.flushTeamTiptopControl(TeamLogic.getTeamByTeamID(teamid))
--					break
--				end
--			end
		end
	end
end

-- 判断目标是否可交
function aimCanFinish(aimID, copyID, roomID, human)
	local aimRecord = aimRoomStatus[roomID][aimID]

	if aimRecord == nil or aimRecord.status == CopyDefine.AIM_STATUS_FINISHED then
		return CopyDefine.COPY_AIM_FINISH_FAIL_NOT_ACCEPTED
	end
	
	if aimRecord.status ~= CopyDefine.AIM_STATUS_DOING_CAN_FINISH then
		return CopyDefine.COPY_AIM_FINISH_FAIL_NOT_ENOUGH_NUM
	end
	
	local aimConfig = ExcelCopyAimConf[copyID][aimID]
	-- 距离合法性判断
	if aimConfig.endNpcId ~= 0 and ExcelNpcConf.npc[aimConfig.endNpcId].exist_map == 1 then
		if ExcelNpcConf.npc[aimConfig.endNpcId].mapID ~= Map.scene_id_to_map_id[human.scene_id] then
			return CopyDefine.COPY_AIM_FINISH_FAIL_POS
		end
		
		--[[local len = Util.dist(human.x, human.y, ExcelNpcConf.npc[aimConfig.endNpcId].mapX, ExcelNpcConf.npc[aimConfig.endNpcId].mapY)
		if len > 500 then
			return CopyDefine.COPY_AIM_FINISH_FAIL_POS
		end--]]
	end

	if aimConfig.targetTime > 0 then
		local now = os.time()
		if now - aimRecord.beginTime > aimConfig.targetTime then
			return CopyDefine.COPY_AIM_FINISH_FAIL_TIME
		end
	end

	return CopyDefine.COPY_AIM_FINISH_OK
end

-- 交目标
function aimDoFinish(aimID, copyID, roomID)
	if aimRoomStatus[roomID] == nil then return end
	if aimRoomStatus[roomID][aimID] == nil then return end
	if aimRoomStatus[roomID][aimID].status == CopyDefine.AIM_STATUS_FINISHED then return end
	if aimRoomStatus[roomID][aimID].status == CopyDefine.AIM_STATUS_FAIL then return end
	
	if Copy.roomDatas[copyID][roomID].finishCode then return end
	
	local aimConfig = ExcelCopyAimConf[copyID][aimID]
	
	AimAction.playMovie(copyID, roomID, aimConfig.movie3)
	AimAction.raiseSceneEvent(copyID, roomID, aimConfig.event3)
			
	-- 发送奖励 背包没满就丢背包 背包满了就发邮件
	local humanList = Copy.getCopyHumanList(copyID, roomID)
	for i = 1, #humanList do
		local humanTemp = humanList[i]
		local itemCount, itemGrids = getRewardItem(humanTemp, copyID, aimID, aimConfig, true)
		if itemCount == 0 then 
			break 
		end
		
		local resultGrid = {}
		local expAdd = nil
		local yinliangAdd = nil
		local bindYuanbaoAdd = nil
		for j = 1, itemCount do
			if itemGrids[j].id == ItemDefine.ITEM_ID_JINGYAN then
				expAdd = itemGrids[j].cnt
			elseif itemGrids[j].id == ItemDefine.ITEM_ID_YINLIANG then
				yinliangAdd = itemGrids[j].cnt
		  elseif itemGrids[j].id == ItemDefine.ITEM_ID_BIND_YUANBAO then
		    bindYuanbaoAdd = itemGrids[j].cnt
			else
				resultGrid[#resultGrid + 1] = itemGrids[j]
			end
		end
		
		if expAdd then
			local worldExpAdd =  0 -- math.ceil(expAdd * WorldExpAdd.getWorldExpAdd(humanTemp) / 100)
			ObjHuman.addExp(humanTemp, expAdd, worldExpAdd) 
		end
		if yinliangAdd then
			ObjHuman.addYinliang(humanTemp, yinliangAdd, "copy_process_reward") 
		end
		if bindYuanbaoAdd then
		  ObjHuman.addBindYuanbao(humanTemp, bindYuanbaoAdd, "copy_process_reward") 
		end

		BagLogic.sendReward(humanTemp._id, resultGrid,Lang.COPY_PROCESS_REWARD_TITLE, Lang.COPY_PROCESS_REWARD_CONTENT, "copy_process_reward")
	end
	
	if aimConfig.mainLoop == CopyDefine.AIM_TYPE_MAIN then
		-- 如果这个目标有挑战目标 而且挑战目标没有完成 那么放弃这个挑战目标
		for tempID, tempConfig in pairs(ExcelCopyAimConf[copyID]) do
			if tempConfig.mainLoop == CopyDefine.AIM_TYPE_CHALLENGE and tempConfig.prevAimId == aimID then
				if aimRoomStatus[roomID][tempID].status ~= CopyDefine.AIM_STATUS_FINISHED then
					aimDoFail(tempID, copyID, roomID)
				end				
				-- break
			end
		end
	end
			
	aimRoomStatus[roomID][aimID].status = CopyDefine.AIM_STATUS_FINISHED
	aimRoomStatus[roomID][aimID].finishTime = os.time()
	sendAimStatus(copyID, roomID, aimID)
	if aimConfig.nextAimId == -1 then
		-- 副本结束
		Copy.roomFinish(copyID, roomID, CopyDefine.COPY_FINISH_OK, Lang.COPY_FINISH_OK)	
	elseif aimConfig.nextAimId ~= 0 then
		-- 有后续的目标
		aimDoAccept(aimConfig.nextAimId, copyID, roomID)
	end
	
	CopyCallback.onDoAimFinish(copyID, roomID, aimID)
end

-- 目标失败
function aimDoFail(aimID, copyID, roomID, exit)
	if aimRoomStatus[roomID] == nil then return end
	if aimRoomStatus[roomID][aimID] == nil then return end
	if aimRoomStatus[roomID][aimID].status == CopyDefine.AIM_STATUS_FINISHED then return end
	
	aimRoomStatus[roomID][aimID].status = CopyDefine.AIM_STATUS_FAIL
	sendAimStatus(copyID, roomID, aimID)
	if exit then
	   Copy.roomFinish(copyID, roomID, CopyDefine.COPY_FINISH_TIMEOUT, Lang.COPY_FINISH_TIMEOUT) 
	end
end

-- 怪物被打死回调
function aimMonsterDieCB(killer, monster, monsterID, copyID, roomID)
	if aimRoomStatus[roomID] == nil then return end
	if ExcelCopyAimConf[copyID] == nil then return end
	
	local tempTable = {}
	Util.copyTable(aimRoomStatus[roomID], tempTable)
	
	-- 注意 这里要遍历两次 第一次先处理挑战目标 第二次才处理其他目标 因为完成主线目标的时候可能会放弃挑战目标
	for aimID, aimRecord in pairs(tempTable) do
		if aimRecord.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH then
			local aimConfig = ExcelCopyAimConf[copyID][aimID]
			if aimConfig.mainLoop == CopyDefine.AIM_TYPE_CHALLENGE then
				local logicFunc = AimAction.aimActionFuncList[aimConfig.target].monsterDie
				if logicFunc then logicFunc(killer, monster, monsterID, aimID, aimConfig, copyID, roomID) end
			end
		end
	end
	
	for aimID, aimRecord in pairs(tempTable) do
		if aimRecord.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH then
			local aimConfig = ExcelCopyAimConf[copyID][aimID]
			if aimConfig.mainLoop ~= CopyDefine.AIM_TYPE_CHALLENGE then
				local logicFunc = AimAction.aimActionFuncList[aimConfig.target].monsterDie
				if logicFunc then logicFunc(killer, monster, monsterID, aimID, aimConfig, copyID, roomID) end
			end
		end
	end
end

-- 采集物被采集回调
function aimCollectDieCB(killer, collect, collectID, copyID, roomID)
	if aimRoomStatus[roomID] == nil then return end
	if ExcelCopyAimConf[copyID] == nil then return end
	
	local tempTable = {}
	Util.copyTable(aimRoomStatus[roomID], tempTable)
	
	-- 注意 这里要遍历两次 第一次先处理挑战目标 第二次才处理其他目标 因为完成主线目标的时候可能会放弃挑战目标
	for aimID, aimRecord in pairs(tempTable) do
		if aimRecord.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH then
			local aimConfig = ExcelCopyAimConf[copyID][aimID]
			if aimConfig.mainLoop == CopyDefine.AIM_TYPE_CHALLENGE then
				local logicFunc = AimAction.aimActionFuncList[aimConfig.target].collectDie
				if logicFunc then logicFunc(killer, collect, collectID, aimID, aimConfig, copyID, roomID) end
			end
		end
	end
	
	for aimID, aimRecord in pairs(tempTable) do
		if aimRecord.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH then
			local aimConfig = ExcelCopyAimConf[copyID][aimID]
			if aimConfig.mainLoop ~= CopyDefine.AIM_TYPE_CHALLENGE then
				local logicFunc = AimAction.aimActionFuncList[aimConfig.target].collectDie
				if logicFunc then logicFunc(killer, collect, collectID, aimID, aimConfig, copyID, roomID) end
			end
		end
	end
end

-- 玩家被打死回调
function aimRoleDieCB(human, copyID, roomID)
	if aimRoomStatus[roomID] == nil then return end
	
	local copyConfig = ExcelMapConf.copy[copyID]
	if copyConfig.dieFail == 1 then
		Copy.roomFinish(copyID, roomID, CopyDefine.COPY_FINISH_DIE_FAIL, Lang.COPY_FINISH_DIE_FAIL)
	end
end

-- 定时器回调 1秒一次
function aimTimerOneSec(copyID, roomID)
	if aimRoomStatus[roomID] == nil then return end
	if ExcelCopyAimConf[copyID] == nil then return end
	
	local aimID = getDoingMainAim(copyID, roomID)
	local aimConfig = ExcelCopyAimConf[copyID][aimID]
	if aimConfig and aimConfig.targetTime > 0 then
		local now = os.time()
		if now - aimRoomStatus[roomID][aimID].beginTime > aimConfig.targetTime then
			-- 超时 失败
			Copy.roomFinish(copyID, roomID, CopyDefine.COPY_FINISH_TIMEOUT, Lang.COPY_FINISH_TIMEOUT)	
		end
	end
end

-- 地图事件n计数改变
function aimSceneNChange(copyID, roomID)
	if aimRoomStatus[roomID] == nil then return end
	if ExcelCopyAimConf[copyID] == nil then return end
	
	local aimRecord = aimRoomStatus[roomID]
	for aimID, aimInfo in pairs(aimRecord) do
		if aimInfo.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH or aimInfo.status == CopyDefine.AIM_STATUS_DOING_CAN_FINISH then
			local aimConfig = ExcelCopyAimConf[copyID][aimID]
			if aimConfig.target == CopyDefine.COPY_AIM_ACTION_BLANK_N then
				sendAimStatus(copyID, roomID, aimID)
			end
		end
	end
end

--到达某个区域
function aimReachArea(human, aimID)
  local sceneID = human.scene_id
  local copyID = Copy.sceneID2CopyID[sceneID]
  local roomID = Copy.sceneID2Room[sceneID]
  if copyID == nil or roomID == nil then return end
  if aimRoomStatus[roomID] == nil then return end
  if ExcelCopyAimConf[copyID] == nil then return end
  if aimRoomStatus[roomID][aimID] == nil then return end
  local aimRecord =  aimRoomStatus[roomID][aimID] 
  if aimRecord.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH then
      local aimConfig = ExcelCopyAimConf[copyID][aimID]
      local logicFunc = AimAction.aimActionFuncList[aimConfig.target].reachArea
      if logicFunc then logicFunc(aimID, aimConfig, copyID, roomID) end
  end  
end
function getDoingMainAim(copyID, roomID)
	local aimRecord = aimRoomStatus[roomID]
	if aimRecord == nil then return end
	
	for aimID, aimInfo in pairs(aimRecord) do
		if aimInfo.status == CopyDefine.AIM_STATUS_DOING_CANNOT_FINISH or aimInfo.status == CopyDefine.AIM_STATUS_DOING_CAN_FINISH then
			local aimConfig = ExcelCopyAimConf[copyID][aimID]
			if aimConfig.mainLoop == CopyDefine.AIM_TYPE_MAIN then
				return aimID
			end
		end
	end
end

-- 根据目标进度获取进入的mapid, x, y
function getEnterMap(copyID, roomID)
	local aimID = getDoingMainAim(copyID, roomID)
	if aimID then 
		local aimConfig = ExcelCopyAimConf[copyID][aimID]
		if #aimConfig.reborn == 2 then
			return aimConfig.mapID, aimConfig.reborn[1], aimConfig.reborn[2]
		else
			local sceneConfig = ExcelMapConf.scene[aimConfig.mapID]			
			return aimConfig.mapID, sceneConfig.x, sceneConfig.y
		end
	end
end

-- 获取目标进度
function getAimProgress(copyID, roomID)
	local aimID = getDoingMainAim(copyID, roomID)
	if aimID then 
		local aimConfig = ExcelCopyAimConf[copyID][aimID]
		return aimConfig.progress 
	end
	
	return 0
end


function getRewardItem(human, copyID, copyAimID, config, noZeroCntGrid)
	local copyConfig = ExcelMapConf.copy[copyID]
	if copyConfig.rewardLv > 0 and human.db.lv > copyConfig.rewardLv then return 0, RetRewardItem end

	local count = 0
	if config.reward then
		for itemID, itemInfo in pairs(config.reward) do
			if RewardItemGridCache[copyID] == nil then
				RewardItemGridCache[copyID] = {}
			end
			if RewardItemGridCache[copyID][copyAimID] == nil then
				RewardItemGridCache[copyID][copyAimID] = {}
			end
			if RewardItemGridCache[copyID][copyAimID][itemID] == nil then
				local bind = true
				if itemInfo[3] and itemInfo[3] == 0 then bind = false end
				local g = {}
				if not itemInfo[2] then
				  Grid.create(g, itemID, itemInfo[1], bind)					 
				else
					Grid.create(g, itemID, itemInfo[1], bind, ItemDefine.getQualityOut(itemInfo[2]))
				end
				RewardItemGridCache[copyID][copyAimID][itemID] = g
			end
			
			if noZeroCntGrid == nil or itemInfo[1] > 0 then
				count = count + 1
				RetRewardItem[count] = RewardItemGridCache[copyID][copyAimID][itemID]
			end
		end
	end	
	return count, RetRewardItem
end